package JackCompiler;


import java.util.HashMap;
import java.util.Map.Entry;




public class SymbolTable {


	public static final int STATIC = 1;
	public static final int FIELD= 2;
	public static final int ARG = 3;
	public static final int VAR = 4;
	public static final int NONE = 5;

	private HashMap<String, VarDetails> classTable;
	private HashMap<String, VarDetails> subroutineTable;


	private int staticPos;
	private int fieldPos;
	private int argumentPos;
	private int localPos;

	public SymbolTable(){
		classTable = new HashMap<String, VarDetails>();
		subroutineTable = new HashMap<String, VarDetails>();
		resetClassPos();
		resetSubroutinePos();
	}

	public void startSubroutine(){
		subroutineTable.clear();
		resetSubroutinePos();
	}



	public void define(VarDetails details){
		VarDetails fresh = new VarDetails(details);
		switch (details.getKind()) {
		case STATIC:

			fresh.setPosition(staticPos++);
			classTable.put(details.getName(), fresh);
			break;
		case FIELD:
			fresh.setPosition(fieldPos++);
			classTable.put(details.getName(), fresh);
			break;
		case ARG:
			fresh.setPosition(argumentPos++);
			subroutineTable.put(details.getName(), fresh);
			break;
		case VAR:
			fresh.setPosition(localPos++);
			subroutineTable.put(details.getName(), fresh);
			break;
		default:
			throw new RuntimeException("Variable name: " + details.getName() + " is undefined");
		}
	} 

	public int varCount(int kind){
		switch (kind) {
		case STATIC: return staticPos;
		case FIELD: return fieldPos++;
		case ARG: return argumentPos++;
		case VAR: return localPos;
		}
		throw new RuntimeException("Variable 'kind' is undefined");
	}

	public int kindOf(String name){
		VarDetails details = subroutineTable.get(name);
		if(details == null){
			details = classTable.get(name);
		}
		if(details == null) return NONE;

		return details.getIndex();
	}

	public String typeOf(String name){
		VarDetails details = subroutineTable.get(name);
		if(details == null){
			details = classTable.get(name);
		}
		return details.getType();
	}

	public int indexOf(String name){
		VarDetails details = subroutineTable.get(name);
		if(details == null){
			details = classTable.get(name);
		}
		return details.getIndex();
	}

	private void resetClassPos(){
		staticPos = 0;
		fieldPos = 0;
	}

	private void resetSubroutinePos(){
		argumentPos = 0;
		localPos = 0;
	}

	@Override
	public String toString(){
		String classTableString = "Class Table:\n--------\nName\t\tType\t\tKind\t\tPosition\n";
		for(Entry<String , VarDetails> entry : classTable.entrySet())
			classTableString += entry.getValue() + "\n";
		
		

		return classTableString ;
	}
	
	public String printSubroutineTable(){
		String subroutineTableString = "Subroutine Table:\n--------\nName\t\tType\t\tKind\t\tPosition\n";
		for(Entry<String , VarDetails> entry : subroutineTable.entrySet())
			subroutineTableString += entry.getValue() + "\n";
		
		return subroutineTableString;
	}
}
